import { _decorator, Component, error, Node } from 'cc';
import Singleton from './Singleton';
const { ccclass, property } = _decorator;

//绑定操作，
class Listener {
    //消息名字。
    private _msgName: string = '';
    //绑定这个消息的对象。
    private _target: any = null;
    get target() {
        return this._target;
    }
    //响应后要调用的函数。
    private _cb: Function = null;
    get cb() {
        return this._cb;
    }
    //是否是一次的。
    private _isOnce: boolean = null;
    get isOnce() {
        return this._isOnce;
    }
    constructor(msgName: string, taget: any, cb: Function, isOnce: boolean) {
        this._msgName = msgName;
        this._target = taget;
        this._cb = cb;
        this._isOnce = isOnce;
    }

    isEquals(listener: Listener) {
        return this._msgName == listener._msgName
            && this._cb == listener._cb
            && this._target == listener._target;
    }
}

@ccclass('Emitter')
export class Emitter {
    //单例
    private static _instance: Emitter = null;
    static get instance() {
        if (!this._instance) {
            this._instance = new this();
        }
        return this._instance;
    }
    //存储消息名字跟Listener数组。 发送消息后，可以多人响应。
    private _mapListener: Map<string, Listener[]> = new Map();

    //注册接口。
    on(msgName: string, target: any, cb: Function, isOnce: boolean = false) {
        //判断
        if (!msgName || msgName.length <= 0 || !target || !cb) {
            return;
        }
        //通过消息到Map中查找Listener 看这个消息是否已经在这里注册过了。
        let arrListener = this._mapListener.get(msgName);
        //如果不存在，第一次注册。
        if (!arrListener) {
            //创建一个数组。
            arrListener = [];
            //跟消息绑定存储到map
            this._mapListener.set(msgName, arrListener);
        }
        //new一个Listener对象
        let listener = new Listener(msgName, target, cb, isOnce);
        //判断这个对象的这个函数绑定的listener是否已经存在了，如果是，不需要注册。
        for (let listenerIn of arrListener) {
            if (listener.isEquals(listenerIn)) {
                error('已经注册过了');
                return;
            }
        }
        arrListener.push(listener);
    }

    //注册的一次性接口
    once(msgName: string, target: any, cb: Function) {
        this.on(msgName, target, cb, true);
    }


    //消息名字，携带的信息。
    emit(msgName: string, ...rest: any[]) {
        //判断
        if (!msgName || msgName.length <= 0) {
            return;
        }
        //裁剪参数数组
        let args = Array.prototype.slice.call(arguments, 1);
        //先去获取Listener数组
        let arrListener = this._mapListener.get(msgName);
        if (!arrListener) {
            //如果都没有注册，那么都不处理
            return;
        }
        //开始响应
        for (let i = 0; i < arrListener.length; i++) {
            //执行数组中每个Listener对象的cb
            let listener = arrListener[i];
            //执行cb
            listener.cb.apply(listener.target, args);
            //如果这个listener注册的时候是一次性，那么在响应完后，要把他从数组中排除掉。
            if (listener.isOnce) {
                arrListener.splice(i--, 1);
            }
        }

        //如果说响应完后，如果arrListener为空，也没必要留着
        if (arrListener.length <= 0) {
            this._mapListener.delete(msgName);
        }
    }

    //清除消息接口。
    //清空所有。 参数0个
    //清除某个消息  参数1个
    //清除某个消息某个对象   参数2个
    //清除某个消息某个对象某个函数。  参数3个
    off(...rest: any[]) {
        //获取参数数组
        let args = Array.from(arguments);
        let length = args.length;
        //如果参数是0个，那么清空
        if (length <= 0) {
            this._mapListener.clear();
            return;
        }
        //第一个参数必须是字符串，如果不是，那么不做处理。     
        if (typeof args[0] != 'string') {
            error('清除消息第一个参数必须是字符串');
            return;
        }
        let msgName = args[0];
        //如果是一个的，那么就是清除某个消息
        if (length <= 1) {
            this._mapListener.delete(msgName);
            return;
        }
        //如果参数是两个：清除某个消息中的Listener数组中的监听者里注册了某个对象的所有listener
        let arrListener = this._mapListener.get(msgName);
        //遍历这个数组，找到跟第二个参数（对象），含有这个对象的listener删掉。
        if (args[1] instanceof Function) {
            error('参数2要求不是函数');//如果要也行，函数删除函数相关，对象删除对象相关。
            return;
        }
        if (length <= 2) {

            for (let i = 0; i < arrListener.length; i++) {
                if (args[1] == arrListener[i].target) {
                    arrListener.splice(i--, 1);
                }
            }
            //如果空了，那么删掉
            if (arrListener.length <= 0) {
                this._mapListener.delete(msgName);
            }
            return;
        }
        if (length <= 3) {
            for (let i = 0; i < arrListener.length; i++) {
                if (args[1] == arrListener[i].target
                    && args[2] == arrListener[i].cb) {
                    arrListener.splice(i, 1);  //因为不应该存在一个消息里面注册了同个对象的同个函数多次。 
                    break;
                }
            }

            //如果空了，那么删掉
            if (arrListener.length <= 0) {
                this._mapListener.delete(msgName);
            }
        }
    }
}